package mbp.core;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;

import mbp.base.EnumType;
import mbp.base.FeatureType;
import mbp.base.ObjectValue;
import mbp.base.ResourceType;
import mbp.base.ServiceType;
import mbp.base.TimeUnit;
import mbp.exceptions.InvalidFeatureNameException;
import mbp.exceptions.InvalidFeatureTypeException;
import mbp.exceptions.InvalidFeatureValueException;
import mbp.exceptions.InvalidResourceTypeException;
import mbp.exceptions.InvalidSizeException;
import mbp.exceptions.InvalidValueException;
import mbp.exceptions.ParseExpressionErrorException;

/**
 * Imlementuje usuge (Service). Po utworzeniu obiekt jest inicjalizowany wartosciami domyslnymi.
 * Nalezy ustawic parametry uslugi, czyli wartosci cech zasobow wejeciowych i wyjyciowych.
 * @author Wojciech Wialnski
 *
 */
public class Service 
{
	//typ uslugi
	private ServiceType serviceType;
	
	//Podstawowe listy: Zakres wartosci cech zasobow wejsciowych, Zasoby wyjsciowe
	protected List<ResourceValidation> rcvIn;
	protected List<Resource> rcOut;
	
	//Listy rozdzielajace zakresy cech zasobow wejsciowych zaleznie od przeznaczenia: zaliczka / towar / zaplata
	private List<ResourceValidation> rcvInAdvance;
	private List<ResourceValidation> rcvInStuff;
	private List<ResourceValidation> rcvInPay;
	
	//Lista na zasoby otrzymywane w ramach realizacji uslugi
	protected List<Resource> rcInStuff;
	
	//Waznosc oferty czyli czas od momentu utworzenia obiektu do podpisania kontraktu
	protected Integer offerValidTU;
	
	//Terminy dostarczenia zasobow wejsciowych od momentu podpisania kontraktu
	protected List<Integer> stuffValidTU;
	
	//Termin realizacji kontraktu
	protected Integer realzeValidTU;
	
	//Waznoscc wyprodukowanych zasobow wyjsciowych
	protected List<Integer> rcOutValidTU;
	
	//Obiekt zainicjalizowany
	private Boolean initialized;
	
	//Otrzymano i sprawdzono zaliczke
	private boolean advanceRecieved;
	
	//Otrzymano i sprawdzono zasoby towary
	private boolean stuffRecieved;
	
	protected Logger logger = Logger.getLogger(this.getClass());
	
	/**
	 * Konstruktor. Podajemy jako argument typ uslugi. Obiekt zostanie utworzony z wartosciami domyslnymi
	 * @param serviceType
	 */
	public Service(ServiceType serviceType)
	{
		this.serviceType = serviceType;
		
		rcvIn = new ArrayList<ResourceValidation>();
		//resources_in = new ArrayList<ObjectValue<ResourceValidation>>();
		rcOut = new ArrayList<Resource>();
		
		rcOutValidTU = new ArrayList<Integer>();
		stuffValidTU = new ArrayList<Integer>();
		
		rcvInAdvance = new ArrayList<ResourceValidation>();
		rcvInStuff = new ArrayList<ResourceValidation>();
		rcvInPay = new ArrayList<ResourceValidation>();
		
		rcInStuff = new ArrayList<Resource>();
		
		initialized = false;
		advanceRecieved = false;
		stuffRecieved = false;
		
		this.initialize();
		
		//logger.debug("Service " + serviceType.getServiceTypeName() + " Has been created.");
	}
	
	/**
	 * Zwraca typ uslugi
	 * @return
	 */
	public ServiceType getType() {
		return serviceType;
	}
	
	/**
	 * Zwraca jednostki czasu do obliczenia daty waznosci oferty.
	 * @return
	 */
	public Integer getOfferValidTerm()
	{
		return offerValidTU;
	}
	
	/**
	 * Ustawia jednostki czasu waznosci oferty ktora zostanie utworzona na podstawie tej uslugi.
	 * @param value
	 */
	public void setOfferValidTerm(Integer value)
	{
		this.offerValidTU = value;
	}
	
	/**
	 * Ustawia liste z jednostkami czasu dostarczania zasobow wejsciowych. jednostki te sa podstawa do obliczenia dat dostarczania
	 * zasobow wejsciowych od momentu podpisania kotraktu.
	 * @param stuffValidTU
	 */
	public void setResourcesInDeliveryTrems(ArrayList<Integer> stuffValidTU)
	{
		for(int i = 0; i<stuffValidTU.size()-1; i++)
		{
			if(stuffValidTU.get(i+1)<stuffValidTU.get(i))
			{
				logger.error("Wrong values in indexes [" + i + "]=" + stuffValidTU.get(i) + " and [" + (i+1) + "]=" + stuffValidTU.get(i+1) + 
						" New resources delivery terms can not be set !!!");
				return;
			}
		}
		
		// Ustawienie terminow w obiektach rcvInStuff
		for(int i = 0; i<stuffValidTU.size(); i++)
		{
			rcvInStuff.get(i).integerValue = new Integer(stuffValidTU.get(i));
		}
		
		
		
		this.stuffValidTU = stuffValidTU;
	}
	
	/**
	 * Zwraca liste z jednostkami czasu dostarczania zasobow wejsciowych. jednostki te sa podstawa do obliczenia dat dostarczania
	 * zasobow wejsciowych od momentu podpisania kotraktu.
	 * @return
	 */
	public List<Integer> getResourcesInDeliveryTrems()
	{
		return Collections.unmodifiableList(stuffValidTU);
	}
	
	/**
	 * Zwraca jednostki czasu raelizacji kotraktu. Jednostki te sa podstawa do obliczenia daty realizacki kontraktu
	 */
	public Integer getServiceRealizeTerm()
	{
		return realzeValidTU;
	}
	
	/**
	 * Ustawia jednostki czasu raelizacji kotraktu. Jednostki te sa podstawa do obliczenia daty realizacki kontraktu
	 * @param realzeValidTU
	 */
	public void setServiceRealizeTerm(Integer realzeValidTU)
	{
		Integer lastStuff = this.stuffValidTU.get(this.stuffValidTU.size()-1);
		if(realzeValidTU<=lastStuff)
		{
			logger.error("Wrong value=" + realzeValidTU + " The value should be more than " + lastStuff);
			return;
		}
		
		this.realzeValidTU = new Integer(realzeValidTU);
		
		// ustawienie w obiektach rcvInPay
		for(int i = 0; i<rcvInPay.size(); i++)
		{
			rcvInPay.get(i).integerValue = new Integer(realzeValidTU);
		}
	}
	
	/**
	 * Zwraca jednostki czasu okreslajace waznosc produkowanych zasobow.
	 * @return
	 */
	public List<Integer> getResourcesOutValidTerms()
	{
		return rcOutValidTU;
	}
	
	
	
	/**
	 * Wywoluje proces inicjalizacji obiektu Service wartosciami domyslnymi
	 */
	public void initialize()
	{
		ArrayList<ResourceValidation> rvList = new ArrayList<ResourceValidation>();
		ArrayList<Resource> rcList = new ArrayList<Resource>();
		
		
		ArrayList<ResourceType> types_in = (ArrayList<ResourceType>) serviceType.getResourceTypesIn();
		ArrayList<ResourceType> types_out = (ArrayList<ResourceType>) serviceType.getResourceTypesOut(); 
		
		for(int i = 0; i<types_in.size(); i++)
		{
			ResourceValidation rv = new ResourceValidation(types_in.get(i));
			rvList.add(rv);
		}
		
		for(int i = 0; i<types_out.size(); i++)
		{
			//00000000-0000-0000-0000-000000000000
			Resource rc = new Resource(types_out.get(i), "00000000-0000-0000-0000-000000000000");
			SetDefaultValues(rc);
			rcList.add(rc);
		}
		//System.out.println("out: " + rcList.size() + "  in: " + rvList.size());
		//logger.debug("initialize: created " + rcList.size() + " Resource's and " + rvList.size() + " ResourceValidation's");
		initializeService(rcList, rvList);
	}
	
	/**
	 * Ustawia wartosci domyslne zasobu 
	 * @param res - Zasob ktoremu zostana ustawione wartosci domyslne
	 */
	public void SetDefaultValues(Resource res)
	{
		Iterator<String> it = res.getType().getFeaturesCollection().keySet().iterator();
		while (it.hasNext()) 
		{
			String key = (String)it.next();
			try 
			{
				FeatureType type = res.getFeatureType(key);
				switch(type)
				{
				case INT:
					res.setFeatureValue(key, 0);										
					break;
				case FLOAT:
					res.setFeatureValue(key, Float.parseFloat("0.0"));
					break;
				case ENUM:
					res.setFeatureValue(key, 0);
				default:				
					break;
				}
				
				res.setOwner(this.serviceType.getServiceTypeName());
				//Calendar currentDate = Calendar.getInstance();
				//res.SetValidDate(currentDate.getTime());
			} 
			catch (InvalidFeatureNameException e) 
			{
				logger.error("InvalidFeatureNameException", e);
			} 
			catch (InvalidFeatureTypeException e) 
			{
				logger.error("InvalidFeatureTypeException", e);
			} 
			catch (InvalidFeatureValueException e) 
			{
				logger.error("InvalidFeatureValueException", e);
			}
			catch (Exception e)
			{
				logger.error("Exception", e);
			}
			
		}

	}
	
	/**
	 * Inicjalizacja obiektu. Iniclalizacja jest konieczna aby obiekt mogl realizowac usluge danego typu.
	 * @param resourcesOut
	 * Podajemy zasoby wzorcowe jakie sa produkowane przez usluge.
	 * W procesie produkcji jest tworzona kopia tych zasobow 
	 * @param resourcesValidationsIn
	 * Podajemy zakres akceptowalnych cech zasobow potrzebnych do realizacji uslugi.
	 */
	private void initializeService(ArrayList<Resource> resourcesOut, ArrayList<ResourceValidation> resourcesValidationsIn)
	{
		
		try {
			setResourcesIn(resourcesValidationsIn);
			setResourcesOut(resourcesOut);
			initialized = true;
		} catch (InvalidSizeException e) {
			logger.error("InvalidSizeException", e);
			initialized = false;
		} catch (InvalidResourceTypeException e) {
			logger.error("InvalidResourceTypeException", e);
			initialized = false;
		}catch (Exception e) {
			logger.error("Exception", e);
			initialized = false;
		}
	}
	
	
	/**
	 * Metoda czesciowa procesu inicjalizacji uslugi
	 * @param resourcesValidationsIn
	 * @throws InvalidSizeException
	 * @throws InvalidResourceTypeException
	 */
	private void setResourcesIn(ArrayList<ResourceValidation> resourcesValidationsIn) throws InvalidSizeException, InvalidResourceTypeException
	{
		if(resourcesValidationsIn.size() != serviceType.getResourceTypesIn().size())
		{
			throw new InvalidSizeException();
		}
		
		rcvIn.clear();
		
		List<Integer> stuffValidTU_tmp = new ArrayList<Integer>();
		
		ArrayList<ResourceType> types_in = (ArrayList<ResourceType>) serviceType.getResourceTypesIn();
		for(int i = 0; i<types_in.size(); i++)
		{
			if(types_in.get(i).getResourceTypeName().compareTo(resourcesValidationsIn.get(i).getType().getResourceTypeName())!=0)
			{
				throw new InvalidResourceTypeException();
			}
			
			rcvIn.add(resourcesValidationsIn.get(i));
			//stuffValidSec.add(e)
			
			String point = (String) resourcesValidationsIn.get(i).getType().getValue();
			char p = point.charAt(0);
			switch(p)
			{
			case 'a':
				rcvInAdvance.add(resourcesValidationsIn.get(i));
				//System.out.println("-------------------> advance");
				break;
			case 's':
				rcvInStuff.add(resourcesValidationsIn.get(i));
				
				//Domyslny termin dostarczania zasobow wejsciowych - wszystkie 3600 sec
				stuffValidTU_tmp.add(3600);
				//System.out.println("-------------------> stuff");
				break;
			case 'p':
				rcvInPay.add(resourcesValidationsIn.get(i));
				//System.out.println("-------------------> pay");
				break;
			}
		}
		
		//czas dostarczenia zasobow wejsciowych advance
		for(int i = 0; i<rcvInAdvance.size(); i++)
		{
			rcvInAdvance.get(i).integerValue = new Integer(0);
		}
		
		//domyslne czasy dostarczenia zasobow wejsciowych stuff
		setResourcesInDeliveryTrems((ArrayList<Integer>) stuffValidTU_tmp);
		
		//domyslna waznosc oferty
		offerValidTU = 3600;
		
		//domyslny termin realizacji uslugi
		setServiceRealizeTerm(7200);
		
		//ustawienie koniecznosci dostarczenia zaliczki i towarow
		if(rcvInAdvance.size() == 0)
		{
			advanceRecieved = true;
		}
		if(rcvInStuff.size() == 0)
		{
			stuffRecieved = true;
		}
	}
	
	/**
	 * Metoda czesciowa procesu inicjalizacji uslugi. Ustawienie zasobow produkowanych przez usluge.
	 * @param resources
	 * @throws InvalidSizeException
	 * @throws InvalidResourceTypeException
	 */
	private void setResourcesOut(ArrayList<Resource> resources) throws InvalidSizeException, InvalidResourceTypeException
	{
		if(resources.size() != serviceType.getResourceTypesOut().size())
		{
			throw new InvalidSizeException();
		}
		
		rcOut.clear();
		ArrayList<ResourceType> types_out = (ArrayList<ResourceType>) serviceType.getResourceTypesOut();
		for(int i = 0; i<types_out.size(); i++)
		{
			if(types_out.get(i).getResourceTypeName().compareTo(resources.get(i).getType().getResourceTypeName())!=0)
			{
				throw new InvalidResourceTypeException();
			}
			
			rcOut.add(i, resources.get(i));
			
			//domyslna waznosc wyprodukownych zasobow
			rcOutValidTU.add(i, 3600);
		}		
	}
	
	/**
	 * Zwarca liste zasobow produkowanych przez usluge. UWAGA Metoda do wykorzystania jedynie w celach informacyjnych.
	 * @return
	 */
	public ArrayList<Resource> getResourcesOut()
	{
		return (ArrayList<Resource>) rcOut;
	}
	
	
	/**
	 * Zwraca liste obiektow ResourceValidation okreslajacych zakres cech wymaganych zasobow wejsciowych.
	 * @param point - Rodzaj zasobow wejsciowych. 0 - zaliczka, 1 - towar, 2 - zaplata
	 * @return
	 */
	public ArrayList<ResourceValidation> getResourcesIn(int point)
	{
		switch(point)
		{
		case 0:
			return (ArrayList<ResourceValidation>) rcvInAdvance;
		case 1:
			return (ArrayList<ResourceValidation>) rcvInStuff;
		case 2:
			return (ArrayList<ResourceValidation>) rcvInPay;
		default:
			return (ArrayList<ResourceValidation>) rcvIn;		
		}
	}
	
	/**
	 * Sprawdza czy produkowane przez usluge zasoby spelnia podane warnuki.
	 * @param validationList Lista obiektow ResourceValidation
	 * @return
	 */
	public Boolean validateResourcesOut(ArrayList<ResourceValidation> validationList)
	{
		Boolean result  = true;
		
		for(int i = 0; i < rcOut.size(); i++)
		{
			try {
				if( !validationList.get(i).validateCondition(rcOut.get(i)) )
				{
					return false;
				}
			} catch (ParseExpressionErrorException e) {
				// TODO Auto-generated catch block
				logger.error("ParseExpressionErrorException", e);
				return false;
			}
		}
		
		return result;
	}
	
	/**
	 * REALIZACJA USLUGI:
	 * Dodaje i sprawdza liste zasobow potrzebnych jako zaliczka do realizacji uslugi. 
	 * Jezeli usluga nie wymaga zaliczki metode wywolujemy z parametrem null lub z pusta lista.
	 * @param rcAdvance
	 * @return
	 */
	public boolean addResourcesAdvance(ArrayList<Resource> rcAdvance)
	{
		//Sprawdzenie czy serwis jest zainicjalizowany
		if(!initialized)
		{
			//System.out.println(this.getClass().getName() + " Service not initialized");
			logger.error("Service not initialized");
			return false;
		}
		
		if(advanceRecieved)
		{
			logger.error("Advance not needed or allrady recieved");
			return false;
		}
		
		if(rcAdvance == null)
		{
			if(rcvInAdvance.size()==0)
			{
				this.advanceRecieved = true;
				return true;
			}
		}
		
		if(rcAdvance.size() != rcvInAdvance.size())
		{
			//System.out.println(this.getClass().getName() + " rcAdvance.size() != rcAdvance.size()");
			logger.error("Got advance resources cout is: " + rcAdvance.size() + ". Count should be: " + rcvInAdvance.size());
			return false;
		}
		
		for(int i = 0; i<rcvInAdvance.size(); i++)
		{
			try {
				//Sprawdzenie czy przekazane zasoby spelniaja warunki
				int quantity = rcvInAdvance.get(i).getQuantity();
				if(quantity==0)
				{
					logger.debug("Service: " + this.serviceType.getServiceTypeName() + 
					           " Resource advance: " + rcvInAdvance.get(i).getType().getResourceTypeName() +
					           " Not needed. Expected quantity: 0");
					continue;
				}
				Boolean vResult = rcvInAdvance.get(i).validateCondition(rcAdvance.get(i));
				
				logger.debug("Service: " + this.serviceType.getServiceTypeName() + 
						           " Resource: " + rcAdvance.get(i).getType().getResourceTypeName() +
						           " Condition: " + rcvInAdvance.get(i).getCondition() +
						           " Validate result: " + vResult);
				
				if(!vResult)
				{
					return false;
				}
			} catch (ParseExpressionErrorException e) {
				// TODO Auto-generated catch block
				logger.error("ParseExpressionErrorException", e);
				return false;
			}
		}
		this.advanceRecieved = true;
		
		return true;
	}
	
	/**
	 * REALIZACJA USLUGI:
	 * Dodaje pojedynczy zasob jako material. UWAGA: Zasoby musza byc dodawane w kolejnosci wystepujace w definicji uslugi
	 * @param rcStuff
	 * @return
	 */
	public boolean addResourceStuff(Resource rcStuff)
	{
		//Sprawdzenie czy serwis jest zainicjalizowany
		if(!initialized)
		{
			//System.err.println("ERROR: " + this.getClass().getName() + " Service not initialized");
			logger.error("Service not initialized");
			return false;
		}
				
		//Sprawdzenie czy dostarczono zaliczke. na razie pozwala sie dodawac zasoby pomimo braku zaliczki
		if(!advanceRecieved)
		{
			logger.warn("Advance not recieved");
		}
		
		//Sprawdzenie czy dodano juz wszystkie zasoby
		if(stuffRecieved)
		{
			logger.error("All needed resources have already beed added!!! Not possible to add more Resources");
			return false;
		}
		
		//Index na kolejny zasob
		int index = rcInStuff.size();
		
		//Typ kolejnego zasobu
		String type = rcvInStuff.get(index).getType().getResourceTypeName();
		
		//Ilosc dobra w zasobie, jezeli = 0
		int quantity = rcvInStuff.get(index).getQuantity();
		if(quantity==0)
		{
			rcInStuff.add(null);
			if(rcInStuff.size() == rcvInStuff.size())
			{
				this.stuffRecieved = true;
			}
			logger.debug("Service: " + this.serviceType.getServiceTypeName() + 
			           " Resource stuff: " + rcvInStuff.get(index).getType().getResourceTypeName() +
			           " Not needed. Expected quantity: 0");
			return true;
		}
		
		if(rcStuff.getType().getResourceTypeName().compareTo(type)!=0)
		{
			logger.error("Wrong type: " + rcStuff.getType().getResourceTypeName() + ", Expected: " + type);
			return false;
		}
		
		try {
			boolean vResult = rcvInStuff.get(index).validateCondition(rcStuff);
			
			logger.debug("Service: " + this.serviceType.getServiceTypeName() + 
			           " Resource: " + rcvInStuff.get(index).getType().getResourceTypeName() +
			           " Condition: " + rcvInStuff.get(index).getCondition() +
			           " Validate result: " + vResult);
			
			if(vResult)
			{
				rcInStuff.add(rcStuff);
			}
			else
			{
				return false;
			}
		} catch (ParseExpressionErrorException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		if(rcInStuff.size() == rcvInStuff.size())
		{
			this.stuffRecieved = true;
		}
		
		return true;
	}
	
	/**
	 * REALIZACJA USLUGI:
	 * Dodaje / Sprawdza liste zasobow potrzebnych jako materialy, zasoby do realizacji uslugi
	 * @param rcStuffList
	 */
	public Boolean addResourcesStuff(ArrayList<Resource> rcStuffList)
	{
		//Sprawdzenie czy serwis jest zainicjalizowany
		if(!initialized)
		{
			//System.err.println("ERROR: " + this.getClass().getName() + " Service not initialized");
			logger.error("Service not initialized");
			return false;
		}
		
		if(rcStuffList.size() != rcvInStuff.size())
		{
			//System.err.println("ERROR: " + this.getClass().getName() + " rcStuff.size() != rcInStuff.size()");
			logger.error("Got stuff resources cout is: " + rcStuffList.size() + ". Count should be: " + rcvInStuff.size());
			return false;
		}
		
		//Sprawdzenie czy dostarczono zaliczk�
		if(!advanceRecieved)
		{
			//System.err.println("WARNING: " + this.getClass().getName() + " Advance not recieved");
			logger.warn("Advance not recieved");
		}
		
		for(int i = 0; i<rcvInStuff.size(); i++)
		{
			try {
				int quantity = rcvInStuff.get(i).getQuantity();
				if(quantity==0)
				{
					logger.debug("Service: " + this.serviceType.getServiceTypeName() + 
					           " Resource stuff: " + rcvInStuff.get(i).getType().getResourceTypeName() +
					           " Not needed. Expected quantity: 0");
					continue;
				}
				Boolean vResult = rcvInStuff.get(i).validateCondition(rcStuffList.get(i));
				
				logger.debug("Service: " + this.serviceType.getServiceTypeName() + 
				           " Resource: " + rcvInStuff.get(i).getType().getResourceTypeName() +
				           " Condition: " + rcvInStuff.get(i).getCondition() +
				           " Validate result: " + vResult);
				
				if(!vResult)
				{
					return false;
				}
			} catch (ParseExpressionErrorException e) {
				// TODO Auto-generated catch block
				logger.error("ParseExpressionErrorException", e);
				return false;
			}
		}
		
		this.stuffRecieved = true;
		return true;
	}
	
	/**
	 * REALIZACJA USLUGI:
	 * Realizuje usluge, produkuje i zwraca liste zasobow wynikowych.
	 * @param rcPay - Lista zasobow potrzebnych jako ostateczna zaplata
	 * @return
	 */
	public List<Resource> executeService(ArrayList<Resource> rcPay)
	{
		List<Resource> resultList = new ArrayList<Resource>();
		
		//Sprawdzenie czy serwis jest zainicjalizowany
		if(!initialized)
		{
			//System.err.println("ERROR: " + this.getClass().getName() + " Service not initialized");
			logger.error("Service not initialized");
			return null;
		}
		
		//Sprawdzenie czy dostarczono wymagana zaliczke
		if(!advanceRecieved)
		{
			//System.err.println("ERROR: " + this.getClass().getName() + " Advance not recieved");
			logger.error("Advance not recieved");
			return null;
		}
		
		//Sprawdzenie czy dostarczono zasoby potrzebne do realizacji uslugi
		if(!stuffRecieved)
		{
			//System.err.println("ERROR: " + this.getClass().getName() + " Stuff not recieved");
			logger.error("Stuff not recieved");
			return null;
		}
		
		//Sprawdzenie zasobow potrzebnych jako zaliczka
		if(rcPay == null)
		{
			 if(rcvInPay.size() != 0)
			 {
				 logger.error("Resources for payment required!!! Needed nuber of resources: " + rcvInPay.size() + " - Recieved NULL");
				 return null;
			 }
		}
		else
		{
			if(rcPay.size() != rcvInPay.size())
			{
				logger.error("Resources for payment required!!! Needed nuber of resources: " + rcvInPay.size() + " - Recieved: " + rcPay.size());
				return null;
			}
		}
		
		
		for(int i = 0; i<rcvInPay.size(); i++)
		{
			try {
				int quantity = rcvInPay.get(i).getQuantity();
				if(quantity==0)
				{
					logger.debug("Service: " + this.serviceType.getServiceTypeName() + 
					           " Resource pay: " + rcvInPay.get(i).getType().getResourceTypeName() +
					           " Not needed. Expected quantity: 0");
					continue;
				}
				Boolean vResult = rcvInPay.get(i).validateCondition(rcPay.get(i));
				
				logger.debug("Service: " + this.serviceType.getServiceTypeName() + 
				           " Resource: " + rcPay.get(i).getType().getResourceTypeName() +
				           " Condition: " + rcvInPay.get(i).getCondition() +
				           " Validate result: " + vResult);
				
				if(!vResult)
				{
					return null;
				}
			} catch (ParseExpressionErrorException e) {
				// TODO Auto-generated catch block
				logger.error("ParseExpressionErrorException", e);
				return null;
			}
		}
		
		//resources_out.get(0).
		//Resource rc = new Resource(resourceType, uuid)
		//System.out.println("resources_out.size(): " + resources_out.size());
		
		//Produkowanie nowych zasobow wyjsciowych na podstawie wzorca umieszczonego w tablicy resources_out 
		for(int i = 0; i<rcOut.size(); i++)
		{
			Resource rc = new Resource(rcOut.get(i).getType());
			rc.setOwner(this.serviceType.getServiceTypeName());
			Calendar calendar = Calendar.getInstance();
			//calendar.add(Calendar.SECOND, rcOutValidTU.get(i));
			calendar.add(Calendar.YEAR, 1);
			Date dt = calendar.getTime();
			rc.setValidDate(dt);
			
			HashMap<String, FeatureType> fTypes = rcOut.get(i).getType().getFeaturesCollection();
			Iterator<String> it = fTypes.keySet().iterator();
			while(it.hasNext())
			{
				String key = it.next();
				//System.out.println("[executeService] : key " + key + " hasnext: " + it.hasNext());
				
				FeatureType type = fTypes.get(key);
				try {
					switch(type)
					{
					case INT:
						rc.setFeatureValue(key, (Integer)rcOut.get(i).getFeatureValue(key));
						break;
					case FLOAT:
						rc.setFeatureValue(key, (Float)rcOut.get(i).getFeatureValue(key));
						break;
					case ENUM:
						rc.setFeatureValue(key, rcOut.get(i).getFeatureValue(key).toString());
						break;
					}
						
				} catch (InvalidFeatureNameException e) {
					// TODO Auto-generated catch block
					logger.error("InvalidFeatureNameException", e);
					return null;
				} catch (InvalidFeatureTypeException e) {
					// TODO Auto-generated catch block
					logger.error("InvalidFeatureTypeException", e);
					return null;
				} catch (InvalidFeatureValueException e) {
					// TODO Auto-generated catch block
					logger.error("InvalidFeatureValueException", e);
					return null;
				}
			}
			
			Integer quantity = new Integer(rcOut.get(i).getQuantity());
			try {
				rc.setQuantity(quantity);
			} catch (InvalidValueException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			resultList.add(rc);
		}
		
		advanceRecieved = false;
		stuffRecieved = false;
		rcInStuff.clear();
		
		return resultList;
	}
	
	public boolean getAdvanceRecieved()
	{
		return this.advanceRecieved;
	}
	
	public boolean getStuffRecieved()
	{
		return this.stuffRecieved;
	}
	
	public int getStuffRecievedCount()
	{
		return this.rcInStuff.size();
	}
	

}
